package it.uniroma2.art.coda.imdb;

import it.uniroma2.art.coda.core.CODACore;
import it.uniroma2.art.coda.exception.CODAComponentNotSetException;
import it.uniroma2.art.coda.exception.FelixInitializationException;
import it.uniroma2.art.coda.exception.PRParserException;
import it.uniroma2.art.coda.extension.CODAOSGiManger.Layout;
import it.uniroma2.art.coda.interfaces.IdentityResolverInterface;
import it.uniroma2.art.coda.interfaces.ProjectionRulesDeciderInterface;
import it.uniroma2.art.coda.structures.ARTTriple;
import it.uniroma2.art.coda.structures.BindLabelToExistingARTURIResource;
import it.uniroma2.art.coda.structures.CodaFinalSuggestions;
import it.uniroma2.art.coda.structures.PreviousDecisionSingleElement;
import it.uniroma2.art.coda.structures.PreviousDecisions;
import it.uniroma2.art.coda.structures.SelectedProjectionRules;
import it.uniroma2.art.coda.structures.ResourcesSmartSuggesterStruct;
import it.uniroma2.art.coda.structures.SuggOntologyCoda;
import it.uniroma2.art.owlart.exceptions.ModelAccessException;
import it.uniroma2.art.owlart.exceptions.ModelCreationException;
import it.uniroma2.art.owlart.exceptions.ModelUpdateException;
import it.uniroma2.art.owlart.exceptions.QueryEvaluationException;
import it.uniroma2.art.owlart.exceptions.UnsupportedQueryLanguageException;
import it.uniroma2.art.owlart.exceptions.UnsupportedRDFFormatException;
import it.uniroma2.art.owlart.io.RDFFormat;
import it.uniroma2.art.owlart.model.ARTLiteral;
import it.uniroma2.art.owlart.model.ARTNode;
import it.uniroma2.art.owlart.model.ARTResource;
import it.uniroma2.art.owlart.model.ARTURIResource;
import it.uniroma2.art.owlart.model.NodeFilters;
import it.uniroma2.art.owlart.models.OWLArtModelFactory;
import it.uniroma2.art.owlart.models.OWLModel;
import it.uniroma2.art.owlart.models.UnloadableModelConfigurationException;
import it.uniroma2.art.owlart.models.UnsupportedModelConfigurationException;
import it.uniroma2.art.owlart.models.conf.ModelConfiguration;
import it.uniroma2.art.owlart.query.MalformedQueryException;
import it.uniroma2.art.owlart.sesame2impl.factory.ARTModelFactorySesame2Impl;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.uima.UIMAFramework;
import org.apache.uima.analysis_engine.AnalysisEngine;
import org.apache.uima.analysis_engine.AnalysisEngineProcessException;
import org.apache.uima.jcas.JCas;
import org.apache.uima.pear.tools.PackageBrowser;
import org.apache.uima.pear.tools.PackageInstaller;
import org.apache.uima.resource.ResourceInitializationException;
import org.apache.uima.resource.ResourceSpecifier;
import org.apache.uima.util.InvalidXMLException;
import org.apache.uima.util.XMLInputSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TestAnnotatorAndCODAAndURL {

	static private String[] htmlFilePathArray = { 
			"http://www.imdb.com/title/tt0165832/", //Interstate 60
			"http://www.imdb.com/title/tt0165832/fullcredits#cast", 
			"http://www.imdb.com/title/tt0434409/", // V per vendetta
			"http://www.imdb.com/title/tt0434409/fullcredits#cast", 
			"http://www.imdb.com/title/tt0118276/", // Buffy, l'ammazzavampiri
			"http://www.imdb.com/title/tt0118276/fullcredits#cast",
			"http://www.imdb.com/title/tt0898266/", // The Big Bang Theory 
			"http://www.imdb.com/title/tt0898266/fullcredits#cast",
			"http://www.imdb.com/title/tt0099864/", // IT
			"http://www.imdb.com/title/tt0099864/fullcredits#cast",
		};

	private static Logger logger = LoggerFactory.getLogger(TestAnnotatorAndCODAAndURL.class);

	private String baseUri = "http://art.uniroma2.it";
	private String importedUri = "http://art.uniroma2.it";
	private String rdfInputFilePath = "E:/CODATest/imdb/IMDB.owl";
	private String rdfOutputFilePath = "E:/CODATest/imdb/IMDBOutPut.owl";
	//private String rdfOutputFilePath = "E:/CODATest/imdb/IMDBOutPut-just60filmAndCast.owl";
	//private String rdfOutputFilePath = "E:/CODATest/imdb/IMDBOutPut-just60castAndFilm.owl";

	private Map<String, ProjectionRulesDeciderInterface> pdaMap = new HashMap<String, ProjectionRulesDeciderInterface>();
	private Map<String, IdentityResolverInterface> idaMap = new HashMap<String, IdentityResolverInterface>();
	//private Map<String, ResourcesSmartSuggesterInterface> ssMap = new HashMap<String, ResourcesSmartSuggesterInterface>();

	private String dirComponentsPath = "E:/CODATest/components";

	private String repositoryDirPath = "E:/CODATest/repDir";

	private PreviousDecisions prevDec = new PreviousDecisions();

	//private String pearPathString = "E:\\CODATest\\imdb.pear";
	//private String installedPearString = "E:\\CODATest\\installedPear";
	private String oSGiDirPath = "E:/CODATest/OSGiCache";

	private String prFilePath = "E:/CODATest/imdb/IMDB.pr";
	
	private String tempDir = "tempDir";

	public static void main(String[] args) {
		logger.debug("inizio main TestAnnotator");

		TestAnnotatorAndCODAAndURL testAnnAndCODA = new TestAnnotatorAndCODAAndURL();

		OWLModel owlModel = null;
		CODACore codaCore = null;
		try {
			String pearPathString = "E:\\CODATest\\imdb.pear";
			String installedPearString = "E:\\CODATest\\installedPear";
			//String oSGiDirPath = "E:/CODATest/OSGiCache";
			String descrPathString = testAnnAndCODA.installPear(pearPathString, installedPearString);

			// Create an OWLModel and the triple Store.
			owlModel = testAnnAndCODA.initializeOWLModel();

			// Initialize CODACORE
			codaCore = testAnnAndCODA.initializeCODACore(null, owlModel);

			// set the 3 maps containing all the three different type of modules
			testAnnAndCODA.setMap(codaCore);

			// choose the 3 selected modules
			testAnnAndCODA.setSelectedModule(codaCore);

			// Printing the projection rule

			//if (logger.isDebugEnabled())
			//	codaCore.getProjRuleModel().printModel();

			for (int i = 0; i < htmlFilePathArray.length; ++i) {
				String textToBeAnnotatate = testAnnAndCODA.getTextToBeAnnotated(htmlFilePathArray[i]);

				// use the UIMA AAE to annotate the text
				logger.info("annotating file = " + htmlFilePathArray[i]);
				JCas annotCas = testAnnAndCODA.analyzeText(descrPathString, textToBeAnnotatate);

				// set the jcas in CODA
				codaCore.setJCas(annotCas);

				// process all the UIMA annotation
				testAnnAndCODA.processUIMAAnnotation(codaCore, owlModel);

			}
			// Save the ontology
			testAnnAndCODA.saveRDF(owlModel);

		} catch (IOException e) {
			e.printStackTrace();
		} catch (AnalysisEngineProcessException e) {
			e.printStackTrace();
		} catch (ResourceInitializationException e) {
			e.printStackTrace();
		} catch (InvalidXMLException e) {
			e.printStackTrace();
		} catch (ModelUpdateException e) {
			e.printStackTrace();
		} catch (ModelAccessException e) {
			e.printStackTrace();
		} catch (UnsupportedRDFFormatException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (ModelCreationException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (UnsupportedModelConfigurationException e) {
			e.printStackTrace();
		} catch (UnloadableModelConfigurationException e) {
			e.printStackTrace();
		} catch (FelixInitializationException e) {
			e.printStackTrace();
		} catch (PRParserException e) {
			e.printStackTrace();
		} catch (UnsupportedQueryLanguageException e) {
			e.printStackTrace();
		} catch (MalformedQueryException e) {
			e.printStackTrace();
		} catch (QueryEvaluationException e) {
			e.printStackTrace();
		} catch (CODAComponentNotSetException e) {
			e.printStackTrace();
		} finally {
			try {
				if (codaCore != null)
					codaCore.stopAndClose();
			} catch (ModelUpdateException e) {
				e.printStackTrace();
			}
			logger.info("Program termnated"); // da cancellare
		}
		return;
	}

	public String installPear(String pearPathString, String installedPearString) throws IOException {
		File pearFile = new File(pearPathString);
		File installDir = new File(installedPearString);
		if (installDir.exists()) {
			this.deleteDirectory(installDir);
		}
		PackageBrowser instPear = PackageInstaller.installPackage(installDir, pearFile, true);
		return instPear.getComponentPearDescPath();
	}

	private boolean deleteDirectory(File path) {
		if (path.exists()) {
			File[] files = path.listFiles();
			for (int i = 0; i < files.length; i++) {
				if (files[i].isDirectory()) {
					deleteDirectory(files[i]);
				} else {
					files[i].delete();
				}
			}
		}
		return (path.delete());
	}

	private String getTextToBeAnnotated(String htmlFilePath) throws IOException {
		// read the input file containig the test to be analized
		HttpURLConnection httpcon = null ;
		StringBuilder contents = null;
		try{
			URL url = new URL(htmlFilePath);
			httpcon = (HttpURLConnection) url.openConnection();
			httpcon.setRequestMethod("GET");
			httpcon.addRequestProperty("User-Agent", 
	        		"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)");

			httpcon.setDoOutput(true);
			httpcon.setReadTimeout(10000);
			httpcon.connect();
			
			InputStreamReader inputStreamReader = new InputStreamReader(httpcon.getInputStream());
			BufferedReader br = new BufferedReader(inputStreamReader);
	
			contents = new StringBuilder();
			String line;
	
			while ((line = br.readLine()) != null) {
				contents.append(line);
				contents.append(System.getProperty("line.separator"));
			}
		} catch (MalformedURLException e) {
	          e.printStackTrace();
	      } catch (ProtocolException e) {
	          e.printStackTrace();
	      } catch (IOException e) {
	          e.printStackTrace();
	      }
	      finally
	      {
	          //close the connection, set all objects to null
	          httpcon.disconnect();
	          httpcon.setRequestProperty("Connection", "close");
	      }
		return contents.toString();
	}

	private JCas analyzeText(String descrPathString, String textToBeAnnotatate) throws IOException,
			ResourceInitializationException, AnalysisEngineProcessException, InvalidXMLException {
		// pass the txt read to the AE (which is an AAE). To do this read the AAE descriptor and then execute
		// the AAE
		XMLInputSource in;
		ResourceSpecifier specifier;
		AnalysisEngine ae;
		JCas annotCas;

		// in = new XMLInputSource(aggregateAEFilePath);
		in = new XMLInputSource(descrPathString);
		specifier = UIMAFramework.getXMLParser().parseResourceSpecifier(in);
		ae = UIMAFramework.produceAnalysisEngine(specifier);
		ae.setConfigParameterValue("Encoding", "UTF-8");
		annotCas = ae.newJCas();
		annotCas.setDocumentText(textToBeAnnotatate);
		ae.process(annotCas);
		return annotCas;
	}

	private OWLModel initializeOWLModel() throws ModelUpdateException, FileNotFoundException, IOException,
			ModelAccessException, UnsupportedRDFFormatException, ClassNotFoundException,
			ModelCreationException, InstantiationException, IllegalAccessException,
			UnsupportedModelConfigurationException, UnloadableModelConfigurationException {

		/*
		 * String owlArtModelFactoryImplClassName =
		 * "it.uniroma2.art.owlart.sesame2impl.factory.ARTModelFactorySesame2Impl"; Class<? extends
		 * ModelFactory> owlArtModelFactoryImplClass = (Class<? extends ModelFactory>)
		 * Class.forName(owlArtModelFactoryImplClassName); OWLArtModelFactory artModelFact =
		 * OWLArtModelFactory.createModelFactory( owlArtModelFactoryImplClass.newInstance());
		 */
		OWLArtModelFactory artModelFact = OWLArtModelFactory
				.createModelFactory(new ARTModelFactorySesame2Impl());
		String mcClassName = "it.uniroma2.art.owlart.sesame2impl.models.conf.Sesame2PersistentInMemoryModelConfiguration";
		Class mcClass = Class.forName(mcClassName);
		ModelConfiguration modelConf = artModelFact.createModelConfigurationObject(mcClass);
		OWLModel owlModel = artModelFact.loadOWLModel(baseUri, repositoryDirPath, modelConf);
		owlModel.setBaseURI(baseUri);
		owlModel.setDefaultNamespace(baseUri + "#");
		owlModel.clearRDF();
		owlModel.addRDF(new File(rdfInputFilePath), importedUri, RDFFormat.RDFXML, NodeFilters.MAINGRAPH);

		return owlModel;
	}

	private CODACore initializeCODACore(JCas annotCas, OWLModel owlModel)
			throws FelixInitializationException, PRParserException {
		File oSGiDir = new File(oSGiDirPath);
		CODACore codaCore = new CODACore();
		//codaCore.initialize(annotCas, oSGiDir, dirComponentsPath, false, prFilePath, owlModel, prevDec);
		codaCore.initialize(oSGiDir, oSGiDir, Layout.Folded, owlModel, prevDec, new File(tempDir));
		return codaCore;
	}

	private void setMap(CODACore codaCore) {
		pdaMap = codaCore.getProjectionRulesDeciderMap();
		//idaMap = codaCore.getIdentityResolverMap();
		//ssMap = codaCore.getResourcesSmartSuggesterMap();
	}

	private void setSelectedModule(CODACore codaCore) {
		// Choose the 5 components from the 5 lists, at the moment the first of the lists which are not null
		// are choosen
		String key;
		/*if (pdaMap.isEmpty() == false) {
			key = pdaMap.keySet().iterator().next();
			ProjectionRulesDeciderInterface pda = pdaMap.get(key);
			codaCore.setProjectionRulesDecider(pda);
		}
		if (idaMap.isEmpty() == false) {
			key = idaMap.keySet().iterator().next();
			IdentityResolverInterface ida = idaMap.get(key);
			codaCore.setIdentityResolver(ida);
		}
		if (ssMap.isEmpty() == false) {
			key = ssMap.keySet().iterator().next();
			ResourcesSmartSuggesterInterface ss = ssMap.get(key);
			codaCore.setResourcesSmartSuggester(ss);
		}*/
	}

	private void processUIMAAnnotation(CODACore codaCore, OWLModel owlModel) throws ModelUpdateException,
			UnsupportedQueryLanguageException, ModelAccessException, MalformedQueryException,
			QueryEvaluationException, CODAComponentNotSetException, PRParserException {
		SuggOntologyCoda suggOntCoda;
		// PrevAnnProjectedList prevAnnProjList = new PrevAnnProjectedList(null);

		codaCore.setProjectionRulesModel(new File(prFilePath));
		
		while (codaCore.isAnotherAnnotationPresent()) {
			logger.debug("\n\n");

			suggOntCoda = codaCore.processNextAnnotation();
			logger.debug(
					//suggOntCoda.getAnnotation().getCoveredText() + 
					" type: "+ suggOntCoda.getAnnotation().getType().toString() + "\t"
					+ suggOntCoda.getAnnotation().getBegin() + " -> " + suggOntCoda.getAnnotation().getEnd());

			//SelectedProjectionRules selProjRules = suggOntCoda.getSelProjRules();
			//BindLabelToExistingARTURIResource bindLabels = suggOntCoda.getBindLabels();
			//ResourcesSmartSuggesterStruct smartSuggs = suggOntCoda.getResSmartSuggestions();
			//CodaFinalSuggestions codaSuggs = suggOntCoda.getCodaFinalSuggs();

			/*logger.debug("%%%Selected Projection Rule:");
			List<ProjectionRule> projRulesList = selProjRules.getProjRuleList();
			for (ProjectionRule projRule : projRulesList) {
				logger.debug("\ttype = " + projRule.getUIMAType() + "\tid: " + projRule.getId());

				logger.debug("%%%Bind Labels:");
				Map<PlaceholderStruct, Map<String, ARTURIResource>> bindMap = bindLabels
						.getPlaceholderToARTURIResMap();
				Iterator<PlaceholderStruct> bindNodeIter = bindMap.keySet().iterator();
				while (bindNodeIter.hasNext()) {
					PlaceholderStruct node = bindNodeIter.next();
					Map<String, ARTURIResource> artUriResMap = bindMap.get(node);
					logger.debug("\t" + node.getName());
					for (ARTURIResource artUriRes : artUriResMap.values())
						logger.debug("\t\t" + artUriRes.getURI());
				}

				logger.debug("%%%Smart Suggestion:");
				Map<PlaceholderStruct, Map<String, ARTURIResource>> smarSugMap = smartSuggs
						.getPlaceholderToARTURIResMap();
				Iterator<PlaceholderStruct> smartSuggIter = smarSugMap.keySet().iterator();
				while (smartSuggIter.hasNext()) {
					PlaceholderStruct node = smartSuggIter.next();
					Map<String, ARTURIResource> artUriResMap = smarSugMap.get(node);
					logger.debug("\t" + node.getName());
					for (ARTURIResource artUriRes : artUriResMap.values())
						logger.debug("\t\t" + artUriRes.getURI());
				}

				logger.debug("%%%Suggested Triple:");
				List<ARTTriple> artTripleList = codaSuggs.getTriplesList();
				for (ARTTriple artTriple : artTripleList) {
					logger.debug("\tTriple:");
					ARTURIResource subjUri = artTriple.getSubjectUri();
					logger.debug("\t\t" + subjUri.getURI());
					ARTURIResource predUri = artTriple.getPredicateUri();
					logger.debug("\t\t" + predUri.getURI());
					if (artTriple.isObjARes()) {
						ARTURIResource objUri = artTriple.getObjectUri();
						logger.debug("\t\t" + objUri.getURI() + "\tURI");
					} else {
						ARTLiteral objLit = artTriple.getObjectLiteral();
						logger.debug("\t\t" + objLit.getLabel() + "\tLiteral");
					}
				}
			}*/
			
			
			// add the suggestion and the just added triple to the prevDec
			List<ARTTriple> addedTripleList = new ArrayList<ARTTriple>();
			for (ARTTriple artTriple : suggOntCoda.getARTTripleList()) {
				ARTResource subject = artTriple.getSubject();
				ARTURIResource predicate = artTriple.getPredicate();
				ARTNode object = artTriple.getObject();
				/*if (artTriple.isObjARes()) {
					object = artTriple.getObjectUri();
				} else { // artTriple.isObjARes == false
					object = artTriple.getObjectLiteral();
				}*/
				owlModel.addTriple(subject, predicate, object);
				addedTripleList.add(artTriple);
			}
			PreviousDecisionSingleElement prevDecSingleElem = new PreviousDecisionSingleElement(
					addedTripleList, suggOntCoda);
			prevDec.addPrevDecSingleElem(prevDecSingleElem);

		}
	}

	private void saveRDF(OWLModel owlModel) throws IOException, ModelAccessException,
			UnsupportedRDFFormatException {
		logger.info("saving rdf to : "+rdfOutputFilePath); // convert to DEBUG
		owlModel.writeRDF(new File(rdfOutputFilePath), RDFFormat.RDFXML, NodeFilters.MAINGRAPH);
	}
}
